home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 November: Tool Chest / Dev.CD Nov 94.toast / Sample Code / System 7.0 Samples / Edition Manager / Subscribe.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-02-13  |  53.0 KB  |  1,118 lines  |  [TEXT/MPS ]

  1. /*------------------------------------------------------------------------------
  2.  *
  3.  *  Apple Developer Technical Support
  4.  *
  5.  *  Edition subscribing routines
  6.  *
  7.  *  Program:    EditionSample
  8.  *  File:       Subscribe.c -   C Source
  9.  *
  10.  *  by:         C.K. Haun <TR>
  11.  *
  12.  *  Copyright © 1990,1991 Apple Computer, Inc.
  13.  *  All rights reserved.
  14.  *
  15.  *------------------------------------------------------------------------------
  16.  * This file handles the Subscribe section of the program.  It also handles some of 
  17.  * the common use routines, like the section options dialog.
  18.  *----------------------------------------------------------------------------*/
  19.  
  20. #define __SUBSCRIBE__
  21.  
  22. #pragma segment Subscribe
  23. #pragma load "EdSampheaders"                                /* see the Buildheaders.c file */
  24.  
  25. #include "EdSampdefines.h"
  26. /* prototypes */
  27. OSErr MyReadSection(SectionHandle theSection);
  28.  
  29. void MyCancelSection(SectionHandle inSection, WindowPtr theWindow);
  30. OSErr MyReadEditionData(Ptr readinPtr, DescType typeToGet, EditionRefNum readRef, Size *howMuch);
  31. void HandleSectionSave(windowCHandle theWind, Boolean writeEm, Boolean dereg, FSSpec *theSpec);
  32. void StoreSubscriber(windowCHandle shortName, SectionHandle secHandle, Handle inRect, Handle pictIn);
  33. pascal short SubExpOptHook(short itemOffset, short itemHit, DialogPtr theDialog, Ptr yourDataPtr);
  34. pascal Boolean SubExpOptFilter(DialogPtr theDialog, EventRecord *theEvent, short itemOffset, short *itemHit, Ptr yourDataPtr);
  35. void PasteSubscription(void);
  36. void CutSubscription(void);
  37. void CopySubscription(void);
  38. void KillClipSub(void);
  39.  
  40. OSErr ReadClipSection(Size readIn, EditionRefNum sRefNum);
  41. void SkipOverSubscriber(windowCHandle inWindow, unsigned short theKey);
  42. extern pascal short ExpOptHook(short itemOffset, short itemHit, DialogPtr theDialog, Ptr yourDataPtr);
  43. extern pascal Boolean ExpOptFilter(DialogPtr theDialog, EventRecord *theEvent, short itemOffset, short *itemHit, Ptr yourDataPtr);
  44.  
  45. /* external references */
  46. extern WindowPtr gActionWindows;
  47. extern WindowPtr gCurrentWindow;
  48. extern WindowPtr gClipWindowPtr;
  49. extern short gWindowCount;
  50. extern OSErr MyUpdateEdition(SectionHandle theSection);
  51. extern OSErr GetSectionHandleFromEvent(AppleEvent *AEin, SectionHandle *theSection);
  52. extern unsigned long gSectionID;
  53. extern void ShowMe(Str255 in, OSErr aevtErr);
  54. extern void MyCancelPublication(SectionHandle inSection);
  55. extern WindowPtr FindSection(SectionHandle inSection);
  56. extern void CheckTextSections(windowCHandle inWindow, short Action);
  57. extern Boolean gShowPub;
  58. extern Boolean gShowSub;
  59. extern Boolean gExpanded;
  60. extern Boolean gResizeSub;
  61. extern short gClipHasContents;
  62. extern SectionHandle gClipSection;
  63. extern PicHandle gClipPict;
  64. extern Handle gScrapData;
  65. extern EditionOpenerProcPtr gOriginalOpener;
  66. extern void ReadDocData(windowCHandle newWindControl, short readRefNum);
  67. extern WindowPtr AddNewWindow(Boolean showIt);
  68. extern OSErr MySetHandleSize(Handle theHandle, Size theSize);
  69. extern void RePackText(textSectionHandle currentSection, TEHandle theTEHandle);
  70. extern textSectionHandle GetTextSection(windowCHandle shortName, SectionType what);
  71. extern textSectionHandle TextSectionFromSecHandle(SectionHandle theSection);
  72.  
  73. /* this point tells EM to center our expanded box, if we're using that feature */
  74. Point expPoint = 
  75. {
  76.     -1, -1
  77. };
  78.  
  79.  
  80.  
  81.  
  82. /* DoSubscribe presents the user with the Subscriber dialog, and allows the user to */
  83. /* subscribe to a PICT type edition, anywhere, anytime.  It also stores the */
  84. /* section handle returned in the window data structure for the current window */
  85. /* You can only subscribe to TEXT if you have a text box open in the current window.  */
  86. /* Optionally, of course, you can put in your own conversion of the TEXT to a PICT and */
  87. /* subscribe to that as such, same as you would with clipboard types. */
  88.  
  89. void DoSubscribe(void)
  90. {
  91.     OSErr myErr;
  92.     SectionHandle secHandle;
  93.     windowCHandle shortName;
  94.     NewSubscriberReply GetSub;
  95.     shortName = (windowCHandle)GetWRefCon(gCurrentWindow);      /* get our struct */
  96.     GetSub.formatsMask = kPICTformatMask;                   /* tell the dialog we only want PICT type editions */
  97.     if ((*shortName)->boxHandle != nil)                     /* is there a text box already? */
  98.         GetSub.formatsMask += kTEXTformatMask;
  99.     /* GetLastEditionContainerUsed gives you either the last edition container used  */
  100.     /* (either pub or sub, since they are the same to the Edition Manager) or if there */
  101.     /* was not a previous container, it fills it with a default container. */
  102.     GetLastEditionContainerUsed(&GetSub.container);
  103.     /* Now ask the user to select an edition to subscribe to */
  104.     if (!gExpanded)
  105.         myErr = NewSubscriberDialog(&GetSub);
  106.     else
  107.         myErr = NewSubscriberExpDialog(&GetSub, expPoint, kExpandedDITL, (ExpDlgHookProcPtr)ExpOptHook,
  108.                                        (ExpModalFilterProcPtr)ExpOptFilter, nil);
  109.     if (myErr != noErr) {                                   /* bail on fail */
  110.         ShowMe("\pNewSubscriberDialog", myErr);
  111.         return;
  112.     }
  113.     if (GetSub.canceled)                                    /* did they cancel the dialog? */
  114.         return;
  115.     HLock((Handle)shortName);
  116.     /* Now create a new section record for the container the user picked.  In other words, the */
  117.     /* Edition manager keeps track of things by the container, and will give you a section */
  118.     /* record that refers to it for you to keep track with.  */
  119.     /* ••• NOTE: Whenever the Edition Manager gives you memory (like the section handle) */
  120.     /* it came out of your heap, and YOU are responsible for disposing of it when you are */
  121.     /* completely done (and have UnRegistered) the section.  If you're not careful about this */
  122.     /* then you'll get creeping memory loss.  */
  123.     /* Now see if the window has ever been saved.  If so, we can store a reference to */
  124.     /* the file in the section */
  125.     if (GetHandleSize((Handle)(*shortName)->fileAliasHandle) == 0) {
  126.         myErr = NewSection(&GetSub.container, nil, stSubscriber, (*shortName)->windowID + gSectionID, sumAutomatic, &secHandle);
  127.     } else {
  128.         /* if the file has been saved once, then we can store a reference to the 'parent' file */
  129.         /* in the edition */
  130.         FSSpec tempSpec;
  131.         Boolean myWasChanged;
  132.         myErr = ResolveAlias(nil, ((*shortName)->fileAliasHandle), &tempSpec, &myWasChanged);
  133.         myErr = NewSection(&GetSub.container, &tempSpec, stSubscriber, (*shortName)->windowID + gSectionID, sumAutomatic,
  134.                            &secHandle);
  135.     }
  136.     if (myErr != noErr) {
  137.         ShowMe("\pNewSection", myErr);
  138.         return;
  139.     }
  140.     /* section successfully gotten.  Add it to the current window section list please */
  141.     /* Handle this in whatever way is appropriate for your application, of course.  */
  142.     /* The main point to remember is that you _must_ keep track of the section handles, */
  143.     /* they are your method (only method) for comunication between your application */
  144.     /* and the Edition Manager, you will be passing sections to the EM, and it will be */
  145.     /* passing them back to you. */
  146.     gSectionID++;                                           /* increment our unique ID */
  147.     StoreSubscriber(shortName, secHandle, nil, nil);
  148.     HUnlock((Handle)shortName);
  149. }
  150.  
  151. /* end DoSubscribe */
  152. /* DoOptions handles the SectionOptions menu selection.  The handle passed */
  153. /* (inSection) is a subscriber OR publisher section, the Edition Manager will figure */
  154. /* out what dialog to display by looking at the section record */
  155. /* ••• BE CAREFUL with the section  handle you pass to the options dialog (or anywhere, for that matter) */
  156. /* A section that has not been registered, or a section containing a bad alias handle, will */
  157. /* cause the options dialog to blow up in unusual and fun ways */
  158. /* This call also includes the expanded section options dialog box with one */
  159. /* extra item, to show how it's used. */
  160. void DoOptions(SectionHandle inSection)
  161. {
  162.     OSErr myErr;
  163.     SectionOptionsReply oreply;
  164.     Boolean subExpansion;
  165.     
  166.     oreply.sectionH = inSection;                            /* put the section passed in the reply record */
  167.     if ((*inSection)->kind == stSubscriber)
  168.         subExpansion = true;
  169.     else
  170.         subExpansion = false;
  171.     myErr = IsRegisteredSection(inSection);
  172.     if (myErr != noErr) {
  173.         ShowMe("\p Bad Section ", myErr);
  174.         return;
  175.     }
  176.     if (subExpansion) {
  177.         myErr = SectionOptionsExpDialog(&oreply, expPoint, kExpandedSubDITL, (ExpDlgHookProcPtr)SubExpOptHook,
  178.                                         (ExpModalFilterProcPtr)SubExpOptFilter, nil);
  179.     } else {
  180.         if (!gExpanded)
  181.             myErr = SectionOptionsDialog(&oreply);          /* run the dialog */
  182.         else
  183.             myErr = SectionOptionsExpDialog(&oreply, expPoint, kExpandedDITL, (ExpDlgHookProcPtr)ExpOptHook,
  184.                                             (ExpModalFilterProcPtr)ExpOptFilter, nil);
  185.     }
  186.     if (myErr != noErr) {
  187.         ShowMe("\pSection Options", myErr);
  188.         return;
  189.     }
  190.     if (oreply.canceled)                                    /* if user canceled */
  191.         return;
  192.     if (oreply.action == sectionReadMsgID) {
  193.         /* if the user clicked 'Get Edition Now' you'll call your section read routine, the same */
  194.         /* one that gets called on a sect read AppleEvent */
  195.         MyReadSection(inSection);
  196.     } else {
  197.         if (oreply.action == sectionWriteMsgID) {
  198.             /* if the user clicked 'Send Edition Now' you'll call your section write routine, the same */
  199.             /* one that gets called on a sect writ AppleEvent */
  200.             MyUpdateEdition(inSection);
  201.         } else {
  202.             if (oreply.action == 'goto') {
  203.                 /* this is the sect scrl (section scroll) event from the dialog */
  204.                 /* the dialog has already taken the action for you, that's it's job */
  205.             } else {
  206.                 if (oreply.action == emCancelSectionDialogRefCon) {
  207.                     /* This is for canceling a section, either pub or sub, you have to make the */
  208.                     /* choice based on what the section is */
  209.                     SectionType tempST;
  210.                     HLock((Handle)inSection);
  211.                     tempST = (*inSection)->kind;            /* what kinda thing is this? */
  212.                     HUnlock((Handle)inSection);
  213.                     
  214.                     MyCancelSection(inSection, FindSection(inSection));
  215.                 }
  216.             }
  217.         }
  218.     }
  219. }
  220.  
  221. /* end DoOptions */
  222.  
  223. /* AEReadSectionHandler is the handler I installed in the AppleEvent manager list for */
  224. /* AppleEvents of the type 'sect' 'read'.  What this means is that whenever I get a */
  225. /* high level event of the type 'sect' 'read' this routine will be dispatched to when I */
  226. /* call AEProcessAppleEvent (in AppleEventM.c).   This is where the actual section data */
  227. /* gets read in, when the Edition Manager tells you the edition is ready to read */
  228. pascal OSErr AEReadSectionHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  229. {
  230. #pragma unused (reply,refIn)
  231.     SectionHandle theSection;
  232.     OSErr myErr;
  233.     
  234.     myErr = GetSectionHandleFromEvent(messagein, &theSection);      /* in AppleEventM.c */
  235.     if (myErr) {
  236.         ShowMe("\pGetSectionHandleFromEvent", myErr);
  237.         return(myErr);
  238.     }
  239.     /* This next step is very important.  Unexpected things can happen to you, */
  240.     /* a section could disappear between the time an event gets posted and when it */
  241.     /* finally gets to your application (particularly since AppleEvents are the lowest in */
  242.     /* the event hierarchy), the section may have been canceled, deleted, disk off-line, or */
  243.     /* whatever.  You must make a current check with the EM to see if the section that */
  244.     /* you are supposed to read. */
  245.     myErr = IsRegisteredSection((SectionHandle)theSection);
  246.     if (myErr) {
  247.         ShowMe("\pRead IsRegisteredSection", myErr);
  248.         return(myErr);
  249.     }
  250.     /* It is a valid section.  Jump to my routine that opens and reads it */
  251.     MyReadSection(theSection);
  252. }
  253.  
  254. /* end AEReadSectionHandler */
  255.  
  256. /* MyReadSection opens and reads the edition data into my window data structure. */
  257. OSErr MyReadSection(SectionHandle theSection)
  258. {
  259.     OSErr readErr;
  260.     OSErr myErr;
  261.     EditionRefNum sRefNum;
  262.     Size dataSize;
  263.     Boolean existed = false;                                /* for setting the display rect */
  264.     /* open the edition and get a ref number */
  265.     SetCursor(*GetCursor(watchCursor));
  266.     myErr = OpenEdition(theSection, &sRefNum);
  267.     if (myErr) {
  268.         ShowMe("\pOpenEdition", myErr);
  269.         return(myErr);
  270.     }
  271.     /* Here we are double-checking the edition.  I'm first checking for PICT data, */
  272.     /* and as a handy side effect, it gives us the size of the data (returned in my */
  273.     /* variable dataSize) for us to use when we read it later */
  274.     if (noErr == (myErr = EditionHasFormat(sRefNum, 'PICT', &dataSize))) {
  275.         /* It does have a pict, read it in */
  276.         register qq, jj;                                    /* loop vars for window search */
  277.         long subIDtofind;
  278.         
  279.         /*  There is already a handle allocated for this picture in the window structure. 
  280.         *   Find it, resize it (since the edition size could have changed) and fill it.
  281.         *       Keep in mind that the section read may happen for a window which is not 
  282.         *       frontmost, so we need to search all the windows to find the ID */
  283.         WindowPtr tempPort;
  284.         Boolean secFound = false;
  285.         SectionHandle *tempPtr;
  286.         SectionRecord *tempRecord;
  287.         Handle tempHandle;
  288.         WindowPtr tempNextWindow;
  289.         Rect *tempRect;
  290.         Rect holdRect;
  291.         Boolean isClip;
  292.         HLock((Handle)theSection);
  293.         subIDtofind = (*theSection)->sectionID;             /* what ID are we reading?  */
  294.         /* check to see if this is the clipboard's section.  If so, let the clipboard */
  295.         /* handle it */
  296.         if ((subIDtofind == (*gClipSection)->sectionID) && (gClipSection != nil))
  297.             return(ReadClipSection(dataSize, sRefNum));
  298.         GetPort(&tempPort);                                 /* save the current port */
  299.         /* search window list now */
  300.         tempNextWindow = gActionWindows;                    /* start at the beginning of the chain */
  301.         for (qq = 0; qq < gWindowCount; qq++) {
  302.             windowCHandle tempWC;
  303.             /* do housekeeping to get to the section handle list */
  304.             tempWC = (windowCHandle)GetWRefCon(tempNextWindow);
  305.             HLock((Handle)tempWC);
  306.             tempHandle = (*tempWC)->subs;                   /* handle containing SectionHandles */
  307.             HLock(tempHandle);
  308.             tempPtr = (SectionHandle *)*tempHandle;
  309.             /* Loop through all our sections until we find this edition */
  310.             for (jj = 0; jj < (*tempWC)->numSubs; jj++) {
  311.                 Handle *newTemp;
  312.                 HLock((Handle)*tempPtr);
  313.                 tempRecord = *(*tempPtr);
  314.                 if (tempRecord->sectionID == subIDtofind) {
  315.                     /* found the section belonging to this read. */
  316.                     /* can't break, since it is conceiveable that the user has more that one subscription in this document */
  317.                     SetPort(tempNextWindow);                /* set the port to the window we found the section in */
  318.                     HLock((*tempWC)->subDataHandle);
  319.                     newTemp = (Handle *)*((*tempWC)->subDataHandle);
  320.                     newTemp += jj;
  321.                     /* if the dataSize returned was -1 then the size was unknown when opened.  */
  322.                     /* in this case, this should only happen with our special opener.  */
  323.                     /* So, if it is -1, then we'll have to handle the read */
  324.                     /* in a series of steps to get the right amount of data */
  325.                     /* For now, I'll leave that out until I put in a custom */
  326.                     /* opener. Watch this space */
  327.                     if (dataSize != -1) {
  328.                         HUnlock(*newTemp);
  329.                         MySetHandleSize(*newTemp, dataSize);
  330.                         HLock(*newTemp);
  331.                     }
  332.                     /* read the pict in */
  333.                     myErr = MyReadEditionData(**newTemp, 'PICT', sRefNum, &dataSize);
  334.                     /* ••••• NOTE: After much discussion with our Human Interface folks and the */
  335.                     /* Edition Manager engineer, we've decided that the interface guidelines */
  336.                     /* for editions will say that reading a subscription does _not_ dirty */
  337.                     /* a document.  A lot of soul-searching went on to make this decision, and */
  338.                     /* we decided this way primarily to keep the user from getting confused.  */
  339.                     /* Editions should be as transparent and automatic as possible, and reminding */
  340.                     /* the user that an edition is a 'special' thing that they have to do */
  341.                     /* unusual things with to make work right will remove some of that */
  342.                     /* automation.  Of course, the 'cached' version of the subscription that */
  343.                     /* you save with the document should be updated when the subscription changes */
  344.                     /* So, the following line was commented out. */
  345.                     /* (*tempWC)->windowDirty = true;  */
  346.                     /* mark window dirty on every read */
  347.                     holdRect = (*(PicHandle)(*newTemp))->picFrame;
  348.                     HUnlock(*newTemp);
  349.                     /* put the picture in the corner, if it didn't exist.  If it did, adjust the rect as
  350.                     *   required */
  351.                     HLock((*tempWC)->subRects);
  352.                     newTemp = (Handle *)*((*tempWC)->subRects);
  353.                     newTemp += jj;
  354.                     /* if the handle is the size of a rect, I've seen this edition before */
  355.                     if (GetHandleSize(*newTemp) == sizeof(Rect)) {
  356.                         existed = true;                     /* it's already been made */
  357.                     } else {
  358.                         HUnlock(*newTemp);
  359.                         MySetHandleSize(*newTemp, sizeof(Rect));        /* new subscription */
  360.                     }
  361.                     HLock(*newTemp);
  362.                     tempRect = (Rect *)*(*newTemp);
  363.                     if (!existed) {
  364.                         tempRect->top = tempRect->left = 0;
  365.                         tempRect->bottom = holdRect.bottom - holdRect.top;
  366.                         tempRect->right = holdRect.right - holdRect.left;
  367.                     } else {
  368.                         InvalRect(tempRect);                /* refresh the old image if the thing was resized */
  369.                         /*          tempRect->bottom = tempRect->top + (holdRect.bottom - holdRect.top);
  370.                                   tempRect->right = tempRect->left + (holdRect.right - holdRect.left);
  371.                           */
  372.                     }
  373.                     InvalRect(tempRect);
  374.                     HUnlock(*newTemp);
  375.                     HUnlock((Handle)*tempPtr);
  376.                     
  377.                 } else {
  378.                     HUnlock((Handle)*tempPtr);
  379.                     tempPtr += 1;
  380.                 }
  381.             }                                               /* section handle loop jj */
  382.             tempNextWindow = (*tempWC)->nextWindow;
  383.             HUnlock(tempHandle);
  384.             HUnlock((Handle)tempWC);
  385.             if (tempNextWindow == nil)
  386.                 break;
  387.             
  388.             /* ••• NOTE: You'll notice that there is no break or exit from this section searching loop */
  389.             /* Why?  Because there may be many subscribers to the same edition.  The user may */
  390.             /* have multiple subscribtions in the same window, or in any of his or her windows. */
  391.             /* Don't assume that there is only one subscriber (unless you require it, which may be */
  392.             /* reasonable for a single document but _not_ for a multi-document application), run */
  393.             /* your whole list each time to be certain everything gets refreshed */
  394.         }                                                   /* window loop qq */
  395.         SetPort(tempPort);                                  /* reset the port to what it was when we entered */
  396.     } else {
  397.         if (noErr == (myErr = EditionHasFormat(sRefNum, 'TEXT', &dataSize))) {
  398.             WindowPtr theWindow;
  399.             windowCHandle tempWC;
  400.             TEHandle tempTEH;
  401.             textSectionHandle theTES;
  402.             long tempStart, tempEnd;
  403.             /* it's a text subscription.  That means we search in the text path, and also need */
  404.             /* to update the TEHandle for the window this goes with */
  405.             theWindow = FindSection(theSection);
  406.             theTES = TextSectionFromSecHandle(theSection);
  407.             HLock((Handle)theTES);
  408.             tempWC = (windowCHandle)GetWRefCon(theWindow);
  409.             tempTEH = (*tempWC)->boxHandle;
  410.             /* save the current TE selection range so that the user is returned to the */
  411.             /* place he or she was before we did the reading, so the text doesn't jump */
  412.             /* around all loony on them */
  413.             tempStart = (*tempTEH)->selStart;
  414.             tempEnd = (*tempTEH)->selEnd;
  415.             
  416.             /* first thing we need to do is remove whatever the current sub data in our */
  417.             /* TE Record is.  if there is any, o'course */
  418.             if ((*theTES)->startChar != (*theTES)->endChar) {
  419.                 TESetSelect((*theTES)->startChar, (*theTES)->endChar, (TEHandle)tempTEH);
  420.                 TEDelete(tempTEH);
  421.             }
  422.             SetHandleSize((*theTES)->theText, dataSize);
  423.             HLock((*theTES)->theText);
  424.             MyReadEditionData(*(*theTES)->theText, 'TEXT', sRefNum, &dataSize);
  425.             /* that gives us the text.  Now we need to adjust our endpoint */
  426.             (*theTES)->endChar = ((*theTES)->startChar) + dataSize;
  427.             /* set insertion point to where we want to be */
  428.             TESetSelect((*theTES)->startChar, (*theTES)->startChar, tempTEH);
  429.             TEInsert(*(*theTES)->theText, dataSize, tempTEH);
  430.             HUnlock((*theTES)->theText);
  431.             HUnlock((Handle)theTES);
  432.             /* reset insertion point to what it once was */
  433.             TESetSelect(tempStart, tempEnd, tempTEH);
  434.         }
  435.     }
  436. }
  437.  
  438. /* end MyReadSection */
  439.  
  440. OSErr MyReadEditionData(Ptr readinPtr, DescType typeToGet, EditionRefNum readRef, Size *howMuch)
  441. {
  442.     OSErr myErr;
  443.     if (myErr = ReadEdition(readRef, typeToGet, readinPtr, howMuch))
  444.         CloseEdition(readRef, false);
  445.     else
  446.         CloseEdition(readRef, true);
  447.     return(myErr);
  448. }
  449.  
  450. /*  HandleSectionSave handles saving and closing of subscribers for
  451. *       a document.  The Boolean flags tell this function wheither to write
  452. *       ouut the data (on save or save/close) and weither to UnRegister
  453. *       the sections (on close).
  454. *       The resource fork is open on entry.
  455. */
  456. /* theWind is locked on entry */
  457. void HandleSectionSave(windowCHandle theWind, Boolean writeEm, Boolean dereg, FSSpec *theSpec)
  458. {
  459.     SectionHandle *theSections;
  460.     Handle *newTemp;
  461.     SectionRecord secRec;
  462.     Handle tempHandle;
  463.     Rect *tempRectPtr;
  464.     register qq;
  465.     OSErr myErr;
  466.     if ((*theWind)->numSubs) {
  467.         Handle *tempPictPtr;
  468.         HLock((*theWind)->subs);
  469.         theSections = (SectionHandle *)*(*theWind)->subs;
  470.         /* and display rectangles */
  471.         HLock((*theWind)->subRects);
  472.         HLock((*theWind)->subDataHandle);
  473.         newTemp = (Handle *)*((*theWind)->subRects);
  474.         tempPictPtr = (Handle *)*((*theWind)->subDataHandle);
  475.         /* loop through the sections */
  476.         for (qq = 0; qq < (*theWind)->numSubs; qq++) {
  477.             /* first update (or create, if needed, the Ed Manger will know) the alias */
  478.             AssociateSection(*theSections, theSpec);
  479.             /* write the section handle out... */
  480.             if (writeEm) {
  481.                 tempHandle = (Handle)*theSections;
  482.                 HandToHand(&tempHandle);
  483.                 HLock((Handle)*theSections);                /* lock down the original section so we can work with it */
  484.                 secRec = *(*(*theSections));                /* just for easier display below */
  485.                 AddResource(tempHandle, rSectionType, secRec.sectionID, "");
  486.                 /* now do the same with the alias record please */
  487.                 tempHandle = (Handle)secRec.alias;
  488.                 HandToHand(&tempHandle);
  489.                 AddResource(tempHandle, rAliasType, secRec.sectionID, "");
  490.                 HUnlock((Handle)*theSections);
  491.                 /* save off the display rect for this sub */
  492.                 tempHandle = *newTemp;
  493.                 HandToHand(&tempHandle);
  494.                 AddResource(tempHandle, 'RECT', secRec.sectionID, "");
  495.                 /* and save out the picture data, so we don't need to immediatly do a */
  496.                 /* section read when the file is opened */
  497.                 tempHandle = *tempPictPtr;
  498.                 HandToHand(&tempHandle);
  499.                 AddResource(tempHandle, 'PICT', secRec.sectionID, "");
  500.             }                                               /* writeEm if */
  501.             
  502.             if (dereg) {
  503.                 UnRegisterSection(*theSections);
  504.                 /* and dispose of the alias handle */
  505.                 DisposHandle((Handle)*(*(*theSections))->alias);
  506.                 /* and the section handle */
  507.                 DisposHandle((Handle)*theSections);
  508.                 /* and the rectangle handle */
  509.                 DisposHandle((Handle)*newTemp);
  510.                 /* picture handle disposed in closewindow */
  511.             }
  512.             theSections += 1;                               /* go to next section handle please */
  513.             newTemp += 1;                                   /* and next rectangle */
  514.         }
  515.         HUnlock((*theWind)->subRects);
  516.         HUnlock((*theWind)->subs);
  517.     }                                                       /* end subscriber save section */
  518.     /* now do the same thing for our publishers please */
  519.     /* Of course, here you'll also write the data if pumAutomatic is set */
  520.     
  521.     if ((*theWind)->numPubs) {
  522.         HLock((*theWind)->pubs);
  523.         theSections = (SectionHandle *)*(*theWind)->pubs;
  524.         /* and display rectangles */
  525.         HLock((*theWind)->pubRects);
  526.         tempRectPtr = (Rect *)*((*theWind)->pubRects);
  527.         
  528.         /* loop through the sections */
  529.         for (qq = 0; qq < (*theWind)->numPubs; qq++) {
  530.             /* first update (or create, if needed, the Ed Manger will know) the alias */
  531.             AssociateSection(*theSections, theSpec);
  532.             /* write the section handle out... */
  533.             if (writeEm) {
  534.                 tempHandle = (Handle)*theSections;
  535.                 HandToHand(&tempHandle);
  536.                 HLock((Handle)*theSections);                /* lock down the original section so we can work with it */
  537.                 secRec = *(*(*theSections));                /* just for easier display below */
  538.                 AddResource(tempHandle, rSectionType, secRec.sectionID, "");
  539.                 /* now do the same with the alias record please */
  540.                 tempHandle = (Handle)secRec.alias;
  541.                 HandToHand(&tempHandle);
  542.                 
  543.                 AddResource(tempHandle, rAliasType, secRec.sectionID, "");
  544.                 HUnlock((Handle)*theSections);
  545.                 /* save off the display rect for this pub */
  546.                 
  547.                 tempHandle = NewHandle(sizeof(Rect));
  548.                 PtrToHand((Ptr)tempRectPtr, &tempHandle, sizeof(Rect));
  549.                 HandToHand(&tempHandle);
  550.                 AddResource(tempHandle, 'RECT', secRec.sectionID, "");
  551.                 if (secRec.mode == pumOnSave) {
  552.                     MyUpdateEdition(*theSections);
  553.                     /* and indicate that this was saved with a document */
  554.                     (*(*theSections))->refCon |= kSavedOnce;        /* OR in our saved flag with type */
  555.                 }
  556.             }                                               /* writeEm if for pubs */
  557.             
  558.             if (dereg) {
  559.                 UnRegisterSection(*theSections);
  560.                 /* first see if this publisher has ever been saved with a document.  If it hasn't */
  561.                 /* then we'll delete it.  */
  562.                 if (((*(*theSections))->refCon & 0xf0) == kNeverSaved) {
  563.                     OSErr myErr;
  564.                     FSSpec deleteSpec;
  565.                     Boolean myWasChanged;
  566.                     ResolveAlias(nil, ((*(*theSections))->alias), &deleteSpec, &myWasChanged);
  567.                     if (myErr = DeleteEditionContainerFile(&deleteSpec)) {
  568.                         ShowMe("\pDelete Editon", myErr);
  569.                     }
  570.                 }
  571.                 
  572.                 /* and dispose of the alias handle */
  573.                 DisposHandle((Handle)*(*(*theSections))->alias);
  574.                 /* and the section handle */
  575.                 DisposHandle((Handle)*theSections);
  576.                 
  577.             }
  578.             theSections += 1;                               /* go to next section handle please */
  579.             tempRectPtr += 1;                               /* and next rectangle */
  580.         }
  581.         HUnlock((*theWind)->pubRects);
  582.         HUnlock((*theWind)->pubs);
  583.     }
  584.     /* now save off any text sections in this document */
  585.     if ((*theWind)->textSections) {
  586.         textSectionHandle tempTS = (*theWind)->textSections;
  587.         do {
  588.             tempHandle = (Handle)(*tempTS)->theSection;
  589.             /* make sure the text is the latest */
  590.             RePackText(tempTS, (*theWind)->boxHandle);
  591.             AssociateSection((SectionHandle)tempHandle, theSpec);
  592.             
  593.             if (writeEm) {
  594.                 HandToHand(&tempHandle);
  595.                 myErr = MemError();
  596.                 if (myErr)
  597.                     ShowMe("\p memerr", myErr);
  598.                 HLock(tempHandle);                          /* lock down the original section so we can work with it */
  599.                 secRec = *(*(SectionHandle)tempHandle);     /* just for easier display below */
  600.                 AddResource(tempHandle, rSectionType, secRec.sectionID, "");
  601.                 /* save the alias */
  602.                 tempHandle = (Handle)secRec.alias;
  603.                 HandToHand(&tempHandle);
  604.                 AddResource(tempHandle, rAliasType, secRec.sectionID, "");
  605.                 /* now save a copy of my whole text record */
  606.                 
  607.                 tempHandle = (Handle)tempTS;
  608.                 HandToHand(&tempHandle);
  609.                 /* use the same ID number as the section, make things easy */
  610.                 /* zap any forward link in this, so StoreSection doesn't get */
  611.                 /* confused when the section is read back in */
  612.                 (*(textSectionHandle)tempHandle)->nextSection = nil;
  613.                 (*(textSectionHandle)tempHandle)->theText = nil;
  614.                 (*(textSectionHandle)tempHandle)->theSection = nil;
  615.                 AddResource(tempHandle, rMyTextRecordType, secRec.sectionID, "");
  616.                 
  617.                 /* and finally, the associated text */
  618.                 tempHandle = (*tempTS)->theText;
  619.                 HandToHand(&tempHandle);
  620.                 AddResource(tempHandle, rMyTextBlock, secRec.sectionID, "");
  621.                 if (secRec.kind == stPublisher && secRec.mode == pumOnSave) {
  622.                     MyUpdateEdition((*tempTS)->theSection);
  623.                     /* and indicate that this was saved with a document */
  624.                     (*(*tempTS)->theSection)->refCon |= kSavedOnce;     /* OR in our saved flag with type */
  625.                 }
  626.             }                                               /* text writeem if */
  627.             
  628.             if (dereg) {
  629.                 UnRegisterSection((SectionHandle)tempHandle);
  630.                 /* first see if this publisher has ever been saved with a document.  If it hasn't */
  631.                 /* then we'll delete it.  */
  632.                 if (((*(*theSections))->refCon & 0xf0) == kNeverSaved && (*(*theSections))->kind == stPublisher) {
  633.                     OSErr myErr;
  634.                     FSSpec deleteSpec;
  635.                     Boolean myWasChanged;
  636.                     ResolveAlias(nil, (*(SectionHandle)tempHandle)->alias, &deleteSpec, &myWasChanged);
  637.                     if (myErr = DeleteEditionContainerFile(&deleteSpec)) {
  638.                         ShowMe("\pSection Save Delete Editon", myErr);
  639.                     }
  640.                 }
  641.                 
  642.                 /* and dispose of the alias handle */
  643.                 DisposHandle((Handle)(*(SectionHandle)tempHandle)->alias);
  644.                 /* and the section handle */
  645.                 DisposHandle((Handle)tempHandle);
  646.                 
  647.             }
  648.             tempTS = (*tempTS)->nextSection;
  649.         } while (tempTS);
  650.         
  651.     }
  652. }
  653.  
  654. /* MyCancelSection cancels this section.  It removes 
  655. *  the section info from our window structure, and also de-registers the
  656. * section with (from) the Edition Manager.  If it's a publisher, it also 
  657. * deletes the edition file 
  658. */
  659. void MyCancelSection(SectionHandle inSection, WindowPtr theWindow)
  660. {
  661.     OSErr myErr;
  662.     windowCHandle shortName;
  663.     SectionHandle *tempPtr;
  664.     Rect *tempRectPtr;
  665.     register qq;
  666.     FSSpec deleteSpec;
  667.     Boolean myWasChanged;
  668.     shortName = (windowCHandle)GetWRefCon(theWindow);
  669.     HLock((Handle)shortName);
  670.     
  671.     /* first thing to do is deregister the thing */
  672.     UnRegisterSection(inSection);
  673.     if ((*inSection)->kind == stPublisher) {                /* only delete publishers */
  674.         ResolveAlias(nil, ((*inSection)->alias), &deleteSpec, &myWasChanged);
  675.         if (myErr = DeleteEditionContainerFile(&deleteSpec)) {
  676.             ShowMe("\pCancel Delete Editon", myErr);
  677.         }
  678.     }
  679.     /* get rid of the alias handle for it */
  680.     DisposHandle((Handle)(*inSection)->alias);
  681.     if ((*inSection)->kind == stPublisher) {
  682.         HLock((*shortName)->pubs);                          /* lock down my list of section handles */
  683.         tempPtr = (SectionHandle *)*(*shortName)->pubs;
  684.         for (qq = 0; qq < (*shortName)->numPubs; qq++) {
  685.             HLock((Handle)*tempPtr);
  686.             if ((*inSection)->sectionID == (*(*tempPtr))->sectionID) {
  687.                 DisposHandle((Handle)inSection);
  688.                 DisposeHandle((Handle)(*(*tempPtr))->alias);
  689.                 DisposHandle((Handle)*tempPtr);
  690.                 HLock((*shortName)->pubRects);
  691.                 tempRectPtr = (Rect *)*((*shortName)->pubRects);
  692.                 tempRectPtr += qq;
  693.                 if (qq != (*shortName)->numPubs) {
  694.                     register ii;                            /* need to move information down */
  695.                     for (ii = qq; ii < ((*shortName)->numPubs) - 1; ii++) {
  696.                         *tempPtr = *(tempPtr + 1);
  697.                         *tempRectPtr = *(tempRectPtr + 1);
  698.                         tempPtr += 1;
  699.                         tempRectPtr += 1;
  700.                     }
  701.                 }
  702.                 (*shortName)->numPubs--;
  703.                 HUnlock((*shortName)->pubs);
  704.                 MySetHandleSize((*shortName)->pubs, GetHandleSize((*shortName)->pubs) - sizeof(Handle));
  705.                 HUnlock((*shortName)->pubRects);
  706.                 MySetHandleSize((*shortName)->pubRects, (GetHandleSize((*shortName)->pubRects) - sizeof(Rect)));
  707.                 
  708.             }
  709.         }
  710.     } else {                                                /* it's a subscriber */
  711.         
  712.         HLock((*shortName)->subs);                          /* lock down my list of section handles */
  713.         tempPtr = (SectionHandle *)*(*shortName)->subs;
  714.         for (qq = 0; qq < (*shortName)->numSubs; qq++) {
  715.             
  716.             HLock((Handle)*tempPtr);
  717.             if ((*inSection)->sectionID == (*(*tempPtr))->sectionID) {
  718.                 SectionHandle removeSection;
  719.                 Handle *tempRectHand;
  720.                 Handle *tempPicHand;
  721.                 Handle *tempPicHand2;
  722.                 removeSection = (*tempPtr);
  723.                 HLock((Handle)removeSection);
  724.                 /* When the user cancels a subscription, you do NOT want to delete the */
  725.                 /* current subscription data (the picture) at this time.  Since the data should be */
  726.                 /* selectable in the document they are working on (text in a text doc, pic in a */
  727.                 /* pic doc, etc) they keep the last subscription data, and delete it */
  728.                 /* seperatly if they'd like */
  729.                 HLock((*shortName)->subRects);
  730.                 HLock((*shortName)->subDataHandle);
  731.                 tempRectHand = (Handle *)*((*shortName)->subRects);
  732.                 tempPicHand = (Handle *)*((*shortName)->subDataHandle);
  733.                 tempRectHand += qq;
  734.                 tempPicHand += qq;
  735.                 
  736.                 /* move the picture over, increase the handle by 1 */
  737.                 (*shortName)->numPicts++;
  738.                 HUnlock((*shortName)->pictHandle);
  739.                 MySetHandleSize((*shortName)->pictHandle, (GetHandleSize((*shortName)->pictHandle) + sizeof(Handle)));
  740.                 HLock((*shortName)->pictHandle);
  741.                 tempPicHand2 = (Handle *)*(*shortName)->pictHandle;
  742.                 tempPicHand2 += ((*shortName)->numPicts) - 1;
  743.                 *tempPicHand2 = *tempPicHand;
  744.                 /* move the rect over also */
  745.                 HUnlock((*shortName)->pictRects);
  746.                 MySetHandleSize((*shortName)->pictRects, (GetHandleSize((*shortName)->pictRects) + sizeof(Handle)));
  747.                 HLock((*shortName)->pictRects);
  748.                 tempPicHand2 = (Handle *)*(*shortName)->pictRects;
  749.                 tempPicHand2 += ((*shortName)->numPicts) - 1;
  750.                 *tempPicHand2 = *tempRectHand;
  751.                 HUnlock((*shortName)->pictRects);
  752.                 HUnlock((*shortName)->pictHandle);
  753.                 if ((qq + 1) != (*shortName)->numSubs) {
  754.                     register ii;                            /* need to move information down */
  755.                     for (ii = qq; ii < ((*shortName)->numSubs) - 1; ii++) {
  756.                         *tempPtr = *(tempPtr + 1);
  757.                         *tempRectHand = *(tempRectHand + 1);
  758.                         *tempPicHand = *(tempPicHand + 1);
  759.                         tempPtr += 1;
  760.                         tempRectHand += 1;
  761.                         tempPicHand += 1;
  762.                     }
  763.                 }
  764.                 (*shortName)->numSubs--;
  765.                 HUnlock((*shortName)->subs);
  766.                 MySetHandleSize((*shortName)->subs, GetHandleSize((*shortName)->subs) - sizeof(SectionHandle));
  767.                 HUnlock((*shortName)->subRects);
  768.                 MySetHandleSize((*shortName)->subRects, (GetHandleSize((*shortName)->subRects) - sizeof(Handle)));
  769.                 
  770.             }
  771.         }
  772.     }
  773.     HUnlock((Handle)shortName);
  774.     /* and clear the highlight */
  775.     if (gShowPub || gShowSub) {
  776.         extern Rect gShowPubRect;
  777.         extern Rect gShowSubRect;
  778.         extern SectionHandle gShowingSecHandle;
  779.         gShowPub = gShowSub = false;
  780.         gShowingSecHandle = nil;
  781.         InvalRect(&gShowPubRect);
  782.         InvalRect(&gShowSubRect);
  783.     }
  784. }
  785.  
  786. /* end MyCancelSection */
  787.  
  788. void StoreSubscriber(windowCHandle shortName, SectionHandle secHandle, Handle inRect, Handle pictIn)
  789. {
  790.     OSErr myErr;
  791.     SectionHandle *tempPtr;
  792.     Handle *tempPicHand;
  793.     Size dataSize;
  794.     EditionRefNum sRefNum;
  795.     /* first we need to determine if this is a PICT or TEXT subscription, since I'm handling */
  796.     /* them differently for drill. */
  797.     myErr = OpenEdition(secHandle, &sRefNum);
  798.     if (myErr = EditionHasFormat(sRefNum, 'PICT', &dataSize))
  799.         (*secHandle)->refCon |= kTextType;
  800.     else
  801.         (*secHandle)->refCon |= kPictType;
  802.     /* Now that little mechanism could screw up, if the formats of the section have been */
  803.     /* changed since the subscription was originally created.  But it'll work here */
  804.     CloseEdition(sRefNum, true);
  805.     
  806.     /* increase our section handle holding handle by the size of a handle */
  807.     if (((*secHandle)->refCon & 0xf) == kPictType) {
  808.         HUnlock((*shortName)->subs);
  809.         MySetHandleSize((*shortName)->subs, GetHandleSize((*shortName)->subs) + sizeof(SectionHandle));
  810.         HLock((*shortName)->subs);
  811.         /* dereference the handle to our section handles in our window structure */
  812.         /* and cast it to a pointer to section handles, since that's what it contains */
  813.         tempPtr = (SectionHandle *)((*(*shortName)->subs) + (sizeof(SectionHandle) * ((*shortName)->numSubs)));
  814.         /* and store our subscriber section */
  815.         *tempPtr = (SectionHandle)secHandle;
  816.         HUnlock((*shortName)->subs);                        /* let it float again */
  817.         /* Here I'm setting up a handle for the picture data contained in the edition we just */
  818.         /* subscribed to, in an array of handles held in the handle subDataHandle  */
  819.         HUnlock((*shortName)->subDataHandle);
  820.         MySetHandleSize((*shortName)->subDataHandle, GetHandleSize((*shortName)->subDataHandle) + sizeof(Handle));  /* allocate */
  821.         HLock((*shortName)->subDataHandle);
  822.         /* deref it */
  823.         tempPicHand = (Handle *)*((*shortName)->subDataHandle);
  824.         tempPicHand += ((*shortName)->numSubs);
  825.         
  826.         if (pictIn == nil)
  827.             *tempPicHand = NewHandle(0);                    /* set up a nil handleo */
  828.         else
  829.             *tempPicHand = pictIn;
  830.         /* ••• NOTE:  You do _NOT_ read the data contained in this section yet! */
  831.         /* All you have done is subscribed to it, the Edition Manager has not told you */
  832.         /* that you can read it!  Wait for the section read event (see below) to get the */
  833.         /* data.  SO I store an empty handle here as a placeholder */
  834.         MoveHHi(*tempPicHand);
  835.         HUnlock((*shortName)->subRects);
  836.         MySetHandleSize((*shortName)->subRects, (GetHandleSize((*shortName)->subRects) + sizeof(Handle)));  /* allocate a new re*/
  837.         myErr = MemError();
  838.         if (myErr)
  839.             ShowMe("\pMemory error ", myErr);
  840.         HLock((*shortName)->subRects);
  841.         /* generate an empty display rectangle handle also */
  842.         tempPicHand = (Handle *)*((*shortName)->subRects);
  843.         tempPicHand += ((*shortName)->numSubs);
  844.         if (inRect == nil)
  845.             *tempPicHand = NewHandle(0);                    /* set up a nil handleo */
  846.         else
  847.             *tempPicHand = inRect;
  848.         MoveHHi(*tempPicHand);
  849.         (*shortName)->numSubs++;                            /* increment our count of subscribers */
  850.         HUnlock((*shortName)->subRects);
  851.         HUnlock((*shortName)->subDataHandle);
  852.     } else {
  853.         if (((*secHandle)->refCon & 0xf) == kTextType) {        /* double checking here */
  854.             textSectionHandle newSection;
  855.             /* get a new text section record */
  856.             if (inRect == nil) {
  857.                 /* this means that it is being created fresh, so we have to get a */
  858.                 /* text section record from my routine */
  859.                 newSection = GetTextSection(shortName, stSubscriber);
  860.                 /* fill it with stuff relating to the section we just created */
  861.                 (*newSection)->publishing = false;
  862.                 (*newSection)->theID = (*secHandle)->sectionID;
  863.                 (*newSection)->theSection = secHandle;
  864.             } else {
  865.                 newSection = (textSectionHandle)inRect;
  866.             }
  867.             /* store it in our window structure */
  868.             if ((*shortName)->textSections) {
  869.                 textSectionHandle tempSection = (*shortName)->textSections;
  870.                 if ((*shortName)->textSections) {
  871.                     while ((*tempSection)->nextSection)
  872.                         tempSection = (*tempSection)->nextSection;
  873.                 }
  874.                 (*tempSection)->nextSection = newSection;
  875.                 
  876.             } else {
  877.                 /* first one */
  878.                 (*shortName)->textSections = newSection;
  879.             }
  880.         }
  881.     }
  882. }
  883.  
  884. pascal short SubExpOptHook(short itemOffset, short itemHit, DialogPtr theDialog, Ptr yourDataPtr)
  885. {
  886.     short myHit;
  887.     short itemType;
  888.     ControlHandle theButton;
  889.     Rect theRect;
  890.     /* first make sure that a sub-dialog is not frontmost */
  891.     /* so we don't filter keys or hits to a sub-dialog */
  892.     if (GetWRefCon((WindowPtr)theDialog) == 'stdf' || GetWRefCon((WindowPtr)theDialog) == 'optn') {
  893.         /* first see if it's the 'first call' item (see the Standard File chapter).  If it is, then */
  894.         /* we preset our check box */
  895.         if (itemHit == -1) {
  896.             /* this gets the handle to our check box, since we know it's one past the last standard item */
  897.             GetDItem(theDialog, itemOffset + 1, &itemType, (Handle *)&theButton, &theRect);
  898.             SetCtlValue(theButton, gResizeSub);             /* and set our current value */
  899.         } else {
  900.             /* only have one item in this expansion, but we'll check the range anyway to be safe */
  901.             myHit = itemHit - itemOffset;                   /* since our item numbers are relative to the total number */
  902.             /* of items in the dialog, and the system may change.  Always do your item numbering based */
  903.             /* on the offset, this will prevent incompatability when the system dialog grows or shrinks */
  904.             if (myHit == 1) {                               /* I only added one item, so this be the one */
  905.                 /* Pass itemHit here, not myHit, since the dialog manager has no idea that this is an */
  906.                 /* additive dialog.  It is counting from the actual start of the DITL, not the start of */
  907.                 /* your custom items */
  908.                 GetDItem(theDialog, itemHit, &itemType, (Handle *)&theButton, &theRect);
  909.                 if (GetCtlValue(theButton))
  910.                     gResizeSub = false;
  911.                 else
  912.                     gResizeSub = true;
  913.                 SetCtlValue(theButton, gResizeSub);
  914.             }
  915.         }
  916.     }
  917.     return(itemHit);                                        /* the return value must be absolute */
  918. }
  919.  
  920. pascal Boolean SubExpOptFilter(DialogPtr theDialog, EventRecord *theEvent, short itemOffset, short *itemHit, Ptr yourDataPtr)
  921. {
  922.     short myHit;
  923.     short itemType;
  924.     ControlHandle theButton;
  925.     Rect theRect;
  926.     /* first make sure that a sub-dialog is not frontmost */
  927.     /* so we don't filter keys or hits to a sub-dialog */
  928.     if (GetWRefCon((WindowPtr)theDialog) == 'stdf' || GetWRefCon((WindowPtr)theDialog) == 'optn') {
  929.         /* standard filter proc kinda stuff here */
  930.         if ((theEvent->what) == keyDown) {
  931.             char tempChar;
  932.             tempChar = theEvent->message & charCodeMask;
  933.             
  934.             if (((tempChar == 'A') || (tempChar == 'a')) && (theEvent->modifiers & cmdKey)) {
  935.                 /* they pressed an A with the command key down, we get to handle it. */
  936.                 GetDItem(theDialog, itemOffset + 1, &itemType, (Handle *)&theButton, &theRect);
  937.                 if (GetCtlValue(theButton))
  938.                     gResizeSub = false;
  939.                 else
  940.                     gResizeSub = true;
  941.                 SetCtlValue(theButton, gResizeSub);
  942.                 return(true);                               /* tell folks we handled it */
  943.             }
  944.         }
  945.     }
  946.     return(false);                                          /* was not a keystroke we wanted */
  947.     
  948. }
  949.  
  950. /* DeleteSubscriber is called by a menu command 'Clear' */
  951.  
  952. void DeleteSubscriber(void)
  953. {
  954.     if (StopAlert(kCanxSub, nil) == 2) {
  955.         MyCancelSection(gShowingSecHandle, FindSection(gShowingSecHandle));
  956.         
  957.     }
  958. }
  959.  
  960. /* end DeleteSubscriber */
  961.  
  962. /* PasteSubscription pastes the section (a subscriber) from the clipboard into the */
  963. /* frontmost window (as you would expect) */
  964. void PasteSubscription(void)
  965. {
  966.     
  967.     windowCHandle tempWC;
  968.     SectionHandle tempHandle;
  969.     AliasHandle tempHandle2;
  970.     Handle tempRectHand;
  971.     FSSpec newFileSpec;
  972.     Boolean myWasChanged;
  973.     Rect tempPRect = {0,0,40,40};
  974.     long myOffset;
  975.     long fred;
  976.     PicHandle tempPicHandle;
  977.     tempRectHand = NewHandle(sizeof(Rect));
  978. /* first see if there is a section handle on the clipboard */
  979. /* kill the current section on the clipboard, if there is one */
  980. /* •••• NEW, we're looking for section handles and aliases on the clipboard.  */
  981.  
  982. /* set up a dummy picture for this incoming section.... */
  983.     if(!gScrapData)gScrapData=NewHandle(0);
  984.     fred=GetScrap(gScrapData, rSectionType, &myOffset);
  985.     if( fred > 0 ){
  986.     myOffset=0;
  987.     /* read in the rect also */
  988.     fred = GetScrap(tempRectHand,'RECT',&myOffset);
  989.     if(fred > 0 ){
  990.     /* and read in the pict */
  991.         myOffset=0;
  992.     GetScrap((Handle)gClipPict,'PICT',&myOffset);
  993.     }
  994.     }
  995.     HLock(tempRectHand);
  996.     tempWC = (windowCHandle)GetWRefCon(gCurrentWindow);
  997.     HLock((Handle)tempWC);
  998.     if(gClipPict){*(Rect *)(*tempRectHand) = (*gClipPict)->picFrame;
  999.     InvalRect(&(*gClipPict)->picFrame);                     /* make sure it gets drawn */
  1000.     } else {
  1001.     *(Rect *)(*tempRectHand)=tempPRect;
  1002.     }
  1003.     /* update the ID of the section to include the master ID of the window yer pasting into */
  1004.     (*gClipSection)->sectionID += (*tempWC)->windowID;
  1005.     StoreSubscriber(tempWC, gClipSection, tempRectHand, (Handle)gClipPict);
  1006.     HUnlock((Handle)tempWC);
  1007.     /* Now, after you paste the subscription, you have to change the subscription on the clipboard. */
  1008.     /* You need to duplicate it, and assign a new ID number, since if the thing is pasted again */
  1009.     /* you could have two subscriptions with the same ID, which would not be nice.  So we do this... */
  1010.     tempHandle = gClipSection;
  1011.     tempHandle2 = (*gClipSection)->alias;
  1012.     HandToHand((Handle *)&tempHandle);
  1013.     HandToHand((Handle *)&tempHandle2);
  1014.     (*tempHandle)->sectionID = gSectionID;
  1015.     (*tempHandle)->alias = tempHandle2;
  1016.     gSectionID++;
  1017.     /* now register the section so the edition manager knows to send you updates */
  1018.     ResolveAlias(nil, tempHandle2, &newFileSpec, &myWasChanged);
  1019.     if ((RegisterSection(&newFileSpec, tempHandle, &myWasChanged))==noErr)
  1020.         gClipSection = tempHandle;
  1021. //    gClipPict = (PicHandle)NewHandle(0);                    /* allocate an empty handle for this picture data */
  1022.     gClipHasContents = kClipHasSub;
  1023.     MyReadSection(tempHandle);
  1024.     
  1025. }
  1026. /* CutSubscription and CopySubscription move the current selection in the active window to the */
  1027. /* ClipBoard.  The main difference here from standard scrap handling is that the scrap you now */
  1028. /* have is dynamic.  The contents of the clipboard can change if the publisher of this subscription */
  1029. /* changes, so you must treat this section as you would any other subscriber */
  1030. /* frontmost window (as you would expect) */
  1031. void CutSubscription(void)
  1032. {
  1033.     CopySubscription();
  1034.     DeleteSubscriber();                                     /* even though they said cut, I want to make sure that they really mean it */
  1035. }
  1036. /* CopySubscriber moves the current display subscriber to the clipboard, making a new */
  1037. /* subscription in the process, since we don't want to have two copies of the same thing */
  1038. void CopySubscription(void)
  1039. {
  1040.     SectionHandle tempHandle;
  1041.     AliasHandle tempHandle2;
  1042.     FSSpec newFileSpec;
  1043.     Boolean myWasChanged;
  1044.     /* First check to see if there is already a section to remove */
  1045.     if (gClipHasContents == kClipHasSub) {
  1046.         KillClipSub();
  1047.     }
  1048.     tempHandle = gShowingSecHandle;
  1049.     /* copy the alias also */
  1050.     tempHandle2 = (*gShowingSecHandle)->alias;
  1051.     HandToHand((Handle *)&tempHandle);
  1052.     HandToHand((Handle *)&tempHandle2);
  1053.     /* create a unique ID for this section.  I'll just use the next section ID */
  1054.     (*tempHandle)->sectionID = gSectionID;
  1055.     (*tempHandle)->alias = tempHandle2;
  1056.     gSectionID++;
  1057.     /* now register the section so the edition manager knows to send you updates */
  1058.     ResolveAlias(nil, tempHandle2, &newFileSpec, &myWasChanged);
  1059.     if ((RegisterSection(&newFileSpec, tempHandle, &myWasChanged))==noErr)
  1060.         gClipSection = tempHandle;
  1061.     gClipPict = (PicHandle)NewHandle(0);                    /* allocate an empty handle for this picture data */
  1062.     gClipHasContents = kClipHasSub;
  1063. /* write the section handle out to the cipboard */
  1064.       ZeroScrap();
  1065.         PutScrap(sizeof(Handle),rSectionType,(Ptr)&tempHandle);
  1066.         PutScrap(sizeof(Rect),'RECT',(Ptr)&gShowSubRect);
  1067.         
  1068.     MyReadSection(tempHandle);
  1069.     
  1070.     InitCursor();                                           /* set to watch by MyReadSection, would normally be reset next pass */
  1071.     /* through the event loop, but NOT if it's being called by Cut, */
  1072.     /* so I'll reset it just to be safe */
  1073. }
  1074.  
  1075. OSErr ReadClipSection(Size readIn, EditionRefNum sRefNum)
  1076. {
  1077.     extern Handle gScrapData;
  1078.     WindowPtr temp;
  1079.     MySetHandleSize((Handle)gClipPict, readIn);
  1080.     HLock((Handle)gClipPict);
  1081.     /* read the pict in */
  1082.     MyReadEditionData((Ptr)*gClipPict, 'PICT', sRefNum, &readIn);
  1083.     HUnlock((Handle)gClipPict);
  1084.     gScrapData = (Handle)gClipPict;
  1085.     if (((WindowPeek)gClipWindowPtr)->visible) {
  1086.         WindowPtr temp;
  1087.         GetPort(&temp);
  1088.         SetPort(gClipWindowPtr);
  1089.         InvalRect(&gClipWindowPtr->portRect);
  1090.         SetPort(temp);
  1091.     }
  1092. }
  1093. /* This kills the current section on the clipboard, since it's being replaced */
  1094. /* and you don't want to receive events for it anymore */
  1095. void KillClipSub(void)
  1096. {
  1097.     UnRegisterSection(gClipSection);
  1098.     DisposHandle((Handle)(*gClipSection)->alias);
  1099.     DisposeHandle((Handle)gClipSection);
  1100.     gClipSection = nil;
  1101.     gClipHasContents = kClipEmpty;
  1102.     if (GetHandleSize((Handle)gClipPict) != nil)
  1103.         KillPicture(gClipPict);
  1104. }
  1105.  
  1106. /* MyGoToPublisher is used if the user was holding down the Option key during a */
  1107. /* double click, to send them to the publisher without seeing the dialog box */
  1108. OSErr MyGoToPublisher(SectionHandle theSection)
  1109. {
  1110.     EditionInfoRecord theEdInfo;
  1111.     
  1112.     GetEditionInfo(theSection, &theEdInfo);
  1113.     GoToPublisherSection(&theEdInfo.container);
  1114. }
  1115.  
  1116.  
  1117. #undef __SUBSCRIBE__
  1118.